// TextBox.java
package exercise.jslide.jslide.model.text;

import exercise.jslide.jslide.controller.TextController;
import exercise.jslide.jslide.utils.EdgePoint;
import exercise.jslide.jslide.utils.SerializableColor;
import exercise.jslide.jslide.model.SlideElement;
import exercise.jslide.jslide.utils.SerializableFont;
import javafx.geometry.Point2D;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.TextArea;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.TextAlignment;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serial;

//文本框
public class TextBox extends SlideElement {
    private String text;//文本内容
    private SerializableFont font;//字体，字号
    private SerializableColor textColor;//颜色
    private TextAlignment alignment;//对齐方式
    private transient Pane textContainer;//父容器
    private transient TextArea textArea;//一个输入类，可以实现多行输入，自动折叠
    private TextStyle textStyle;//文本样式
    public EdgePoint getEdgePoint() {
        return edgePoint;
    }

    private EdgePoint edgePoint;

    //经过验证，文本框和内部内容都能够显示，现在的主要目标是将text变得可以在点击时进行修改，可以尝试创建一个类，这个类可以支持输入，在点击时激活，然后将text更新为输入
    public TextBox() {
        this.text = "双击输入文本";//文本
        this.font = new SerializableFont("Arial", 12);//字体
        this.textColor = new SerializableColor(Color.BLACK);//文本颜色
        this.alignment = TextAlignment.LEFT;//对齐方式
        this.isEditing = false;
        this.textArea = new TextArea();
        this.textArea.setText(text);
        this.textArea.setVisible(false);
        this.textContainer = new Pane();
        this.textContainer.getChildren().add(textArea);
        this.textContainer.setPickOnBounds(false);
        TextController.addTextContainer(textContainer);
        this.textStyle = new TextStyle();
        textArea.setStyle("-fx-font-weight: " + textStyle.getFontWeightString() + "; -fx-font-family: " + font.getFamily() + "; -fx-font-size: " + font.getSize() + "; -fx-font-style: " + textStyle.getFontStyleString() + "; -fx-text-fill: " + textColor.getFXColor().toString().replace("0x", "#") + ";");

    }

    public void startEditing() {
        if (!isEditing) {
            isEditing = true;
            textArea.setText(text);
            textArea.setLayoutX(x);
            textArea.setLayoutY(y);
            textArea.setPrefWidth(width);
            textArea.setPrefHeight(height);
            textArea.setVisible(true);
            textArea.requestFocus();
        }
    }


    private void updateTextBoxSize() {
        // 根据文本内容更新文本框大小
        // 这里需要计算文本的实际大小
        // 根据最小预设，文字预设，绘画预设的三者中的最大值更新文本框大小
        double textWidth = font.getFXFont().getSize() * text.length() * 0.7; // 简单估算
        double textHeight = font.getFXFont().getSize() * 1.5;
        double widthTemp = Math.max(80, textWidth); // 最小宽度50
        double heightTemp = Math.max(40, textHeight); // 最小高度20
        width = Math.max(widthTemp, width);
        height = Math.max(heightTemp, height);
        textArea.setPrefSize(width, height);


    }


    @Override
    public void draw(GraphicsContext gc) {
        gc.save();
        gc.setFont(Font.font(font.getFamily(), textStyle.getFontWeight(), textStyle.getFontPosture(), font.getSize()));
        gc.setFill(textColor.getFXColor());
        gc.setTextAlign(alignment);

        // 如果文本框被选中，绘制背景和TextFields
        //键入文字的事件也发生在文本框被选中的时候。默认情况下的文本框可以是虚线边框表示存在。
        if (isSelected()) {
            drawTextSelectionFrame(gc);
            drawTextControlPoints(gc);
            gc.setFill(Color.LIGHTGRAY.deriveColor(1, 1, 1, 0.3));
            gc.fillRect(x, y, width, height);
        }

        if (isEditing) {
            textArea.setText(text);
            textArea.setLayoutX(x);
            textArea.setLayoutY(y);
            textArea.setPrefWidth(width);
            textArea.setPrefHeight(height);
            //同步字体样式和颜色
            textArea.setStyle("-fx-font-weight: " + textStyle.getFontWeightString() + "; -fx-font-family: " + font.getFamily() + "; -fx-font-size: " + font.getSize() + "; -fx-font-style: " + textStyle.getFontStyleString() + "; -fx-text-fill: " + textColor.getFXColor().toString().replace("0x", "#") + ";");
            textArea.setVisible(true);
            textArea.requestFocus();
        } else {
            text = textArea.getText();
            textArea.setVisible(false);
            updateTextBoxSize();
        }


        // 绘制文本
        gc.setFill(textColor.getFXColor());
//        gc.setFont(font.getFXFont());
        gc.setFont(Font.font(font.getFamily(), textStyle.getFontWeight(), textStyle.getFontPosture(), font.getSize()));
        gc.fillText(text, x, y + font.getSize());


        gc.restore();
    }

    @Override
    public boolean contains(Point2D point) {
        return point.getX() >= x && point.getX() <= x + width &&
                point.getY() >= y && point.getY() <= y + height;
    }

    @Override
    public TextBox clone() {
        TextBox textBox = new TextBox();
        textBox.text = this.text;
        textBox.font = this.font;
        textBox.textColor = this.textColor;
        textBox.alignment = this.alignment;
        textBox.x = this.x;
        textBox.y = this.y;
        textBox.width = this.width;
        textBox.height = this.height;
        return textBox;
    }

    // Getter和Setter
    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
        // 更新文本框大小
//        updateTextBoxSize();

    }

    public SerializableFont getFont() {
        return font;
    }

    public void setFont(SerializableFont font) {
        this.font = font;
    }

    public Color getTextColor() {
        return textColor.getFXColor();
    }

    public void setTextColor(Color textColor) {
        this.textColor = new SerializableColor(textColor);
    }

    public TextAlignment getAlignment() {
        return alignment;
    }

    public void setAlignment(TextAlignment alignment) {
        this.alignment = alignment;
    }


    protected void drawTextSelectionFrame(GraphicsContext gc) {
        gc.setStroke(Color.BLUE);
        gc.setLineDashes(5);
        gc.strokeRect(x - 2, y - 2, width + 4, height + 4);
        gc.setLineDashes(null);
    }

    protected void drawTextControlPoints(GraphicsContext gc) {
        final double SIZE = 6;
        gc.setFill(Color.WHITE);
        gc.setStroke(Color.BLUE);

        // 4个边界顶点的位置
        Point2D[] points = {
                new Point2D(x, y),                    // 左上
                new Point2D(x + width, y),            // 右上
                new Point2D(x + width, y + height),   // 右下
                new Point2D(x, y + height),           // 左下
        };

        for (Point2D p : points) {
            gc.fillRect(p.getX() - SIZE / 2, p.getY() - SIZE / 2, SIZE, SIZE);
            gc.strokeRect(p.getX() - SIZE / 2, p.getY() - SIZE / 2, SIZE, SIZE);
        }
    }

    public void setEdgePoint(Point2D point){
        if(point.getX()>x+width-3 && point.getX()<=x+width+3 && point.getY()>y+height/2-3 && point.getY()<=y+height/2+3){
            edgePoint = EdgePoint.RightMid;
        }
        else if(point.getX()<x+3 && point.getX()>=x-3 && point.getY()>y+height/2-3 && point.getY()<=y+height/2+3){
            edgePoint = EdgePoint.LeftMid;
        }
        else if(point.getY()>y+height-3 && point.getY()<=y+height+3 && point.getX()>x+width/2-3 && point.getX()<=x+width/2+3){
            edgePoint = EdgePoint.MidDown;
        }
        else if(point.getY()<y+3 && point.getY()>=y-3 && point.getX()>x+width/2-3 && point.getX()<=x+width/2+3){
            edgePoint = EdgePoint.MidUp;
        } else if (point.getX()<x+3 && point.getX()>=x-3 && point.getY()<y+3 && point.getY()>=y-3) {
            edgePoint = EdgePoint.LeftUp;
        }
        else if(point.getX()>x+width-3 && point.getX()<=x+width+3 && point.getY()<y+3 && point.getY()>=y-3){
            edgePoint = EdgePoint.RightUP;
        }
        else if(point.getX()<x+3 && point.getX()>=x-3 && point.getY()>y+height-3 && point.getY()<=y+height+3){
            edgePoint = EdgePoint.LeftDown;
        }
        else if(point.getX()>x+width-3 && point.getX()<=x+width+3 && point.getY()>y+height-3 && point.getY()<=y+height+3){
            edgePoint = EdgePoint.RightDown;
        }
        else {
            edgePoint = EdgePoint.noPoint;
        }
//        System.out.println(edgePoint);
    }

    public void reSize(double deltaX,double deltaY){
        if(edgePoint == EdgePoint.noPoint){

        }
        if(edgePoint == EdgePoint.MidDown){
            height = height+deltaY;
        }
        if(edgePoint == EdgePoint.MidUp){
            y = y+deltaY;
            height = height-deltaY;
        }
        if(edgePoint == EdgePoint.LeftMid){
            x = x+deltaX;
            width = width-deltaX;
        }
        if(edgePoint == EdgePoint.RightMid){
            width = width+deltaX;
        }
        if(edgePoint == EdgePoint.LeftUp){
            x = x+deltaX;
            width = width-deltaX;
            y = y+deltaY;
            height = height-deltaY;
        }
        if(edgePoint == EdgePoint.LeftDown){
            height = height+deltaY;
            x = x+deltaX;
            width = width-deltaX;
        }
        if(edgePoint == EdgePoint.RightDown){
            height = height+deltaY;
            width = width+deltaX;
        }
        if(edgePoint == EdgePoint.RightUP){
            y = y+deltaY;
            height = height-deltaY;
            width = width+deltaX;
        }

    }


    public TextArea getTextArea() {
        return textArea;
    }

    @Serial
    private void writeObject(ObjectOutputStream out) throws IOException {
        out.defaultWriteObject(); // 序列化非transient字段
        out.writeUTF(textArea.getText()); // 手动序列化TextArea的内容
    }

    @Serial
    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        in.defaultReadObject(); // 反序列化非transient字段
        textArea = new TextArea(); // 重新创建TextArea对象
        textArea.setText(in.readUTF()); // 手动反序列化TextArea的内容
        textArea.setVisible(false);
        textContainer = new Pane();
        textContainer.getChildren().add(textArea);
        textContainer.setPickOnBounds(false);
        TextController.addTextContainer(textContainer);
    }

    public Pane getTextContainer() {
        return textContainer;
    }

    public void setTextStyle(TextStyle textStyle) {
        this.textStyle = textStyle;
    }
}